

local Element = commonlib.getfield("Window.Elements.Element");
local Input = commonlib.getfield("Window.Elements.Input");
local Select = import("./Select.lua");

local Editor = commonlib.inherit(Element);

Editor:Property("Blockly");                 -- 所属Blockly
Editor:Property("InputField");              -- 编辑的输入字段
Editor:Property("InputEditor");             -- 输入编辑器
Editor:Property("SelectEditor");            -- 下拉选择器
Editor:Property("CurrentEditor");           -- 当前编辑器
Editor:Property("EditType");                -- 编辑器类型

local MAX_INPUT_WIDTH = 600;                -- 最大输入宽度

function Editor:ctor()
end

function Editor:Init(blockly)
    local window = blockly:GetWindow();
    self:InitElement({
        name = "BlocklyEditor",
        attr = {
            style = "position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; background-color: #00000000;",
        }
    }, window, blockly);

    local inputEditor = Input:new():Init({
        name = "input",
        attr = {
            style = "position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; background-color: #00000000; border-width: 0px;",
            onchange = function(_, value) self:OnChange(value) end, 
        }
    }, window, self);
    inputEditor:SetExist(false);
    self:SetInputEditor(inputEditor);
    self:AddChildren(inputEditor);

    local selectEditor = Select:new():Init({
        name = "BlocklySelect",
        attr = {
            style = "position: absolute; left: 0px; top: 0px; width: 0px; height: 0px;",
            onchange = function(_, value) self:OnChange(value) end, 
            onblur = function() self:EndEdit() end 
        }
    }, window, self);
    selectEditor:SetExist(false);
    self:SetSelectEditor(selectEditor);
    self:AddChildren(selectEditor);

    self:SetBlockly(blockly);
    self:SetExist(false);

    return self;
end

function Editor:ApplyStyle()
    Editor._super.ApplyStyle(self);
    local blockly = self:GetBlockly();
    local current_style = self:GetCurrentStyle();
    local current_editor = self:GetCurrentEditor();
    local input_field = self:GetInputField();
    if (not current_editor or not input_field) then return end 

    local editor_current_style = current_editor:GetCurrentStyle();

    local left, top = input_field:GetLeftTop();
    local width, height = input_field:GetWidthHeight();
    local border_radius = height / 2;

    current_style.position = "absolute";
    current_style.left, current_style.top = blockly:LogicXYToViewXY(left, top);
    current_style.width, current_style.height = width, height;

    local edit_type = self:GetEditType();
    if (edit_type == "input") then
        editor_current_style.position = "absolute";
        editor_current_style.left, editor_current_style.top = 0, 0;
        editor_current_style.width, editor_current_style.height = input_field.FIELD_MAX_WIDTH_UNIT_COUNT * input_field:GetUnitSize() + height, height;
        editor_current_style["font-size"] = input_field.FONT_SIZE;
        editor_current_style["padding-left"] = border_radius;
        editor_current_style["padding-right"] = border_radius;
    end
end

function Editor:Show(input_field)
    if (self:IsExist()) then self:Hide() end 
    
    self:SetInputField(input_field);
    if (not input_field) then return end 

    local current_editor = nil;
    local input_field_type = input_field:GetType();
    local input_field_value = input_field:GetValue();

    local current_editor = nil;
    if (input_field_type == "field_input" or input_field_type == "input_value") then
        self:SetEditType("input");
        current_editor = self:GetInputEditor();
        current_editor:SetAttrValue("value", input_field_value);
        current_editor:HandleSelectAll();
    elseif (input_field_type == "field_select" or input_field_type == "input_select") then
        self:SetEditType("select");
        current_editor = self:GetSelectEditor();
        current_editor:SetAttrValue("options", input_field:GetOptions());
        current_editor:SetAttrValue("value", input_field_value);
        current_editor:SetBGColor(input_field:GetBlock():GetColor());
    else
        return ;
    end

    self:SetCurrentEditor(current_editor);
    current_editor:SetExist(true);
    current_editor:FocusIn();

    self:BeginEdit();

    return Editor._super.Show(self);
end

function Editor:Hide()
    self:SetInputField(nil);

    if (not self:IsExist()) then return end

    self:GetCurrentEditor():SetExist(false);

    Editor._super.Hide(self);
end

function Editor:GetMouseElement(x, y)
    local edit_type = self:GetEditType();
    local contain = self:Contain(x, y);
    if (not self:GetInputField()) then return nil end 
    local input_field = self:GetInputField();
    local current_editor = self:GetCurrentEditor();
    local width, height = input_field:GetWidthHeight();
    local ex, ey = self:ScreenXYToElementXY(x, y);
    if (edit_type == "input") then
        if (contain and ex < width) then
            return current_editor; 
        end 
        return nil;
    end
    return current_editor:GetMouseElement(x, y) or (contain and self or nil);
end

function Editor:OnChange(value)
    local input_field = self:GetInputField();
    if (not input_field) then return end 
    input_field:SetValue(value);
    if (self:GetEditType() == "select") then input_field:SetLabel(input_field:GetLabelByValue(value)) end
    input_field:GetTopBlock():UpdateLayout();
end

function Editor:OnMouseDown(event)
    event:Accept();
end

function Editor:OnMouseMove(event)
    event:Accept();
end

function Editor:OnMouseUp(event)
    event:Accept();
    local current_editor = self:GetCurrentEditor();
    if (current_editor) then current_editor:FocusIn() end 
end

function Editor:BeginEdit()
end

function Editor:EndEdit()
end

return Editor;